package com.ssy.lingxi.member.merchant.serviceimpl.web;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.entity.MemberDO;
import com.ssy.lingxi.member.merchant.entity.MemberRoleRuleDO;
import com.ssy.lingxi.member.merchant.entity.RoleDO;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.MemberIdVO;
import com.ssy.lingxi.member.merchant.model.vo.platform.request.*;
import com.ssy.lingxi.member.merchant.model.vo.platform.response.*;
import com.ssy.lingxi.member.merchant.repository.MemberRepository;
import com.ssy.lingxi.member.merchant.repository.RoleRepository;
import com.ssy.lingxi.member.merchant.repository.RoleRuleRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseSiteService;
import com.ssy.lingxi.member.merchant.service.web.IPlatformMemberRoleRuleService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 平台后台 - 会员角色规则配置相关接口
 *
 * @author whm
 * @version 2.0.0
 * @date 2022-03-10
 **/
@Service
public class PlatformMemberRoleRuleServiceImpl implements IPlatformMemberRoleRuleService {
    @Resource
    private MemberRepository memberRepository;

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private RoleRuleRepository roleRuleRepository;

    @Resource
    private IBaseSiteService siteService;

    /**
     * 根据名称，模糊、分页查询会员列表
     *
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<MemberManageVO>> pageMembers(PageMemberByNameVO pageVO) {
        List<MemberRoleRuleDO> roleRuleDOList = roleRuleRepository.findAll();
        Specification<MemberDO> specification = (Specification<MemberDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if (StringUtils.hasLength(pageVO.getMemberName())) {
                list.add(criteriaBuilder.like(root.get("name").as(String.class), "%" + pageVO.getMemberName().trim() + "%"));
            }
            //去除已经配置了角色规则的会员
            if (!CollectionUtils.isEmpty(roleRuleDOList)) {
                list.add(criteriaBuilder.not(criteriaBuilder.in(root.get("id")).value(roleRuleDOList.stream().map(MemberRoleRuleDO::getMemberId).collect(Collectors.toList()))));
            }
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").descending());
        Page<MemberDO> pageList = memberRepository.findAll(specification, page);

        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(memberDO -> {
            MemberManageVO memberManageVO = new MemberManageVO();
            memberManageVO.setMemberId(memberDO.getId());
            memberManageVO.setMemberName(memberDO.getName());
            return memberManageVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 根据名称，模糊、分页查询会员管理列表
     *
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<MemberRoleRuleVO>> pageRuleMembers(PageMemberByNameVO pageVO) {
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").descending());
        Page<MemberRoleRuleDO> pageList;
        if (StringUtils.hasLength(pageVO.getMemberName())) {
            pageList = roleRuleRepository.findAllByMemberNameLike("%" + pageVO.getMemberName().trim() + "%", page);
        } else {
            pageList = roleRuleRepository.findAll(page);
        }

        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(memberRoleRuleDO -> {
            MemberRoleRuleVO memberRoleRuleVO = new MemberRoleRuleVO();
            memberRoleRuleVO.setRoleRuleId(memberRoleRuleDO.getId());
            memberRoleRuleVO.setMemberId(memberRoleRuleDO.getMemberId());
            memberRoleRuleVO.setMemberName(memberRoleRuleDO.getMemberName());
            return memberRoleRuleVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 根据名称，模糊、分页查询角色详情列表
     *
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<RoleRuleManageVO>> pageRoles(PageRoleRuleVO pageVO) {
        Specification<RoleDO> specification = (Specification<RoleDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            //去掉平台角色
            list.add(criteriaBuilder.notEqual(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
            //会员状态为启用
            list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), EnableDisableStatus.ENABLE.getCode()));
            //按名字做模糊查询
            if (StringUtils.hasLength(pageVO.getRoleName())) {
                list.add(criteriaBuilder.like(root.get("roleName").as(String.class), "%" + pageVO.getRoleName().trim() + "%"));
            }
            if (!CollectionUtils.isEmpty(pageVO.getCheckRoleIdList())) {
                list.add(criteriaBuilder.not(criteriaBuilder.in(root.get("id")).value(pageVO.getCheckRoleIdList())));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").descending());
        Page<RoleDO> pageList = roleRepository.findAll(specification, page);

        return Wrapper.success(new PageData<>(pageList.getTotalElements(), getRoleManageVOList(new HashSet<>(pageList.getContent()))));
    }

    /**
     * 查询当前会员适用角色详情列表
     *
     * @param id 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<List<RoleRuleManageVO>> memberRoles(Long id) {
        MemberRoleRuleDO roleRuleDO = roleRuleRepository.findByMemberId(id);
        if (roleRuleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_NO_SUITABLE_ROLE);
        }
        return Wrapper.success(getRoleManageVOList(roleRuleDO.getMemberRoleRule()));
    }

    /**
     * 查询下级会员适用角色详情列表
     *
     * @param id 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<List<RoleRuleManageVO>> subMemberRoles(Long id) {
        MemberRoleRuleDO roleRuleDO = roleRuleRepository.findByMemberId(id);
        if (roleRuleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_SUB_MEMBER_NO_SUITABLE_ROLE);
        }
        return Wrapper.success(getRoleManageVOList(roleRuleDO.getSubMemberRoleRule()));
    }

    /**
     * 查询下级会员适用角色详情列表(注册)
     *
     * @param id 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<List<RoleRuleRegisterVO>> subMemberRolesRegister(Long id) {
        MemberRoleRuleDO roleRuleDO = roleRuleRepository.findByMemberId(id);
        if (roleRuleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_SUB_MEMBER_NO_SUITABLE_ROLE);
        }
        return Wrapper.success(getRoleRuleRegisterVOList(roleRuleDO.getSubMemberRoleRule()));
    }

    /**
     * 选择会员
     *
     * @param headers    Http头部信息
     * @param memberIdVO 接口参数
     */
    @Override
    public Wrapper<MemberSelectVO> selectMember(HttpHeaders headers, MemberIdVO memberIdVO) {
        //判断是否开启SAAS多租户部署
        siteService.isEnableMultiTenancy(headers);

        MemberDO memberDO = memberRepository.findById(memberIdVO.getMemberId()).orElse(null);
        if (memberDO == null) {
            throw new BusinessException(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        MemberSelectVO memberSelectVO = new MemberSelectVO();
        memberSelectVO.setMemberId(memberDO.getId());
        memberSelectVO.setMemberName(memberDO.getName());
        memberSelectVO.setRoleList(getRoleManageVOList(memberDO.getRoles()));

        return Wrapper.success(memberSelectVO);
    }

    /**
     * 新增会员适用角色
     *
     * @param headers    Http头部信息
     * @param roleRuleVO 接口参数
     */
    @Override
    public Wrapper<Void> addRuleRoles(HttpHeaders headers, AddRoleRuleVO roleRuleVO) {
        //判断是否开启SAAS多租户部署
        siteService.isEnableMultiTenancy(headers);

        //查找会员
        MemberDO memberDO = memberRepository.findById(roleRuleVO.getMemberId()).orElse(null);
        if (memberDO == null) {
            throw new BusinessException(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        //先查出数据库对应的记录，如果有就用原来的，如果没有就创建一个
        MemberRoleRuleDO roleRuleDO = roleRuleRepository.findByMemberId(roleRuleVO.getMemberId());
        if (roleRuleDO == null) {
            roleRuleDO = new MemberRoleRuleDO();
            roleRuleDO.setMemberId(memberDO.getId());
            roleRuleDO.setMemberName(memberDO.getName());
        }

        //因为新增和删除都用这个接口，所以这边都是直接根据前端的入参，将数据存入数据库即可
        if (!CollectionUtils.isEmpty(roleRuleVO.getMemberRoleIdList())) {
            roleRuleDO.setMemberRoleRule(roleRuleVO.getMemberRoleIdList().stream().map(RoleDO::new).collect(Collectors.toSet()));
        }
        if (!CollectionUtils.isEmpty(roleRuleVO.getSubMemberRoleIdList())) {
            roleRuleDO.setSubMemberRoleRule(roleRuleVO.getSubMemberRoleIdList().stream().map(RoleDO::new).collect(Collectors.toSet()));
        }

        roleRuleRepository.saveAndFlush(roleRuleDO);
        return Wrapper.success();
    }

    /**
     * 删除会员适用角色
     *
     * @param headers    Http头部信息
     * @param roleRuleVO 接口参数
     */
    @Override
    public Wrapper<Void> delRuleRoles(HttpHeaders headers, DelRoleRuleVO roleRuleVO) {
        //判断是否开启SAAS多租户部署
        siteService.isEnableMultiTenancy(headers);

        MemberRoleRuleDO roleRuleDO = roleRuleRepository.findByMemberId(roleRuleVO.getMemberId());
        if (roleRuleDO == null) {
            throw new BusinessException(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        if (!CollectionUtils.isEmpty(roleRuleVO.getMemberRoleIdList())) {
            roleRuleDO.getMemberRoleRule().removeAll(roleRuleVO.getMemberRoleIdList().stream().map(RoleDO::new).collect(Collectors.toSet()));
        }
        if (!CollectionUtils.isEmpty(roleRuleVO.getSubMemberRoleIdList())) {
            roleRuleDO.getSubMemberRoleRule().removeAll(roleRuleVO.getSubMemberRoleIdList().stream().map(RoleDO::new).collect(Collectors.toSet()));
        }

        roleRuleRepository.saveAndFlush(roleRuleDO);
        return Wrapper.success();
    }

    /**
     * 会员适用角色详情列表
     *
     * @param idVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<MemberRoleRuleDetailVO> getDetails(MemberDetailByIdVO idVO) {
        Long memberId = idVO.getMemberId();
        MemberDO memberDO = memberRepository.findById(memberId).orElse(null);
        if (memberDO == null) {
            throw new BusinessException(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        List<RoleRuleManageVO> memberRoleList = memberRoles(memberId).getData();
        List<RoleRuleManageVO> subMemberRoleList = subMemberRoles(memberId).getData();

        MemberRoleRuleDetailVO detailVO = new MemberRoleRuleDetailVO();
        detailVO.setMemberId(memberId);
        detailVO.setMemberName(memberDO.getName());
        detailVO.setMemberRoleList(memberRoleList);
        detailVO.setSubMemberRoleList(subMemberRoleList);

        return Wrapper.success(detailVO);
    }

    /**
     * 数据提取转换
     *
     * @param roleRule 角色集合
     * @return 查询结果
     */
    private List<RoleRuleManageVO> getRoleManageVOList(Set<RoleDO> roleRule) {
        return roleRule.stream().filter(role -> !MemberRelationTypeEnum.PLATFORM.getCode().equals(role.getRelType()))
                .map(role -> {
                    RoleRuleManageVO roleManageVO = new RoleRuleManageVO();
                    roleManageVO.setRoleId(role.getId());
                    roleManageVO.setRoleName(role.getRoleName());
                    roleManageVO.setRoleTypeEnum(role.getRoleType().getTypeEnum());
                    roleManageVO.setRoleTypeName(role.getRoleType().getRoleTypeName());
                    roleManageVO.setMemberTypeId(role.getMemberType().getId());
                    roleManageVO.setMemberTypeEnum(role.getMemberType().getTypeEnum());
                    roleManageVO.setMemberTypeName(role.getMemberType().getTypeName());
                    roleManageVO.setBusinessTypeId(role.getBusinessType().getId());
                    roleManageVO.setBusinessTypeName(role.getBusinessType().getBusinessTypeName());
                    return roleManageVO;
                }).collect(Collectors.toList());
    }

    /**
     * 数据提取转换
     * 先按memberTypeId聚类，聚类后结果为 TreeMap<RoleRuleRegisterVO,List<MemberBusinessVO>>
     * 然后再将该TreeMap中的value设置进RoleRuleRegisterVO的memberBusinessList属性中
     *
     * @param roleRule 角色集合
     * @return 查询结果
     */
    private List<RoleRuleRegisterVO> getRoleRuleRegisterVOList(Set<RoleDO> roleRule) {
        return roleRule.stream().filter(role -> !MemberRelationTypeEnum.PLATFORM.getCode().equals(role.getRelType()))
                .collect(Collectors.groupingBy(roleDO -> {
                    RoleRuleRegisterVO roleRuleRegisterVO = new RoleRuleRegisterVO();
                    roleRuleRegisterVO.setMemberTypeId(roleDO.getMemberType().getId());
                    roleRuleRegisterVO.setMemberTypeName(roleDO.getMemberType().getTypeName());
                    roleRuleRegisterVO.setMemberTypeEnum(roleDO.getMemberType().getTypeEnum());
                    return roleRuleRegisterVO;
                }, TreeMap::new, Collectors.mapping(roleDO -> {
                    MemberBusinessVO memberBusinessVO = new MemberBusinessVO();
                    memberBusinessVO.setBusinessTypeId(roleDO.getBusinessType().getId());
                    memberBusinessVO.setBusinessTypeName(roleDO.getBusinessType().getBusinessTypeName());
                    return memberBusinessVO;
                }, Collectors.toList()))).entrySet().stream().map(entry -> entry.getKey().quickSetMemberBusinessList(entry.getValue())).collect(Collectors.toList());
    }
}